package com.api.util.repo;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class DtoProperties implements DtoRepository {

	private final PropertiesAppender properties;

	public DtoProperties(String propertiesFile) {
		this.properties = new PropertiesAppender(propertiesFile);
	}

	@Override
	public boolean existsDto(String name, Class<?> dtoClass) {
		String classNamePrefix = getClassNamePrefix(name, dtoClass);
		Map<String, String> props = properties.getProperties(classNamePrefix);
		return !props.isEmpty();
	}

	@Override
	public <T> T getDto(String name, Class<T> dtoClass) {
		String classNamePrefix = getClassNamePrefix(name, dtoClass);
		Map<String, String> props = properties.getProperties(classNamePrefix);
		if (props.isEmpty()) {
			throw new IllegalStateException(String.format("Properties not found for name '%s'", classNamePrefix));
		}
		try {
			T dtoInstance = dtoClass.newInstance();
			Field[] fields = dtoClass.getDeclaredFields();
			for (Field field : fields) {
				String propertyName = getPropertyName(classNamePrefix, field);
				if (props.containsKey(propertyName)) {
					boolean accessible = field.isAccessible();
					field.setAccessible(true);
					field.set(dtoInstance, props.get(propertyName));
					field.setAccessible(accessible);
				}
			}
			return dtoInstance;
		} catch (Exception e) {
			throw new IllegalStateException(String.format("Couln't get dto instance for class '%s'", dtoClass), e);
		}
	}

	@Override
	public void saveDto(String name, Object dto) {
		Map<String, String> map = new HashMap<String, String>();
		String classNamePrefix = getClassNamePrefix(name, dto.getClass());
		try {
			Class<?> dtoClass = dto.getClass();
			Field[] fields = dtoClass.getDeclaredFields();
			for (Field field : fields) {
				boolean accessible = field.isAccessible();
				field.setAccessible(true);
				Object value = field.get(dto);
				field.setAccessible(accessible);

				if (value != null) {
					String propertyName = getPropertyName(classNamePrefix, field);
					map.put(propertyName, String.valueOf(value));
				}
			}
		} catch (Exception e) {
			throw new IllegalStateException(String.format("Couln't save dto instance '%s'", dto), e);
		}
		properties.appendProperties(map);
	}

	private String getClassNamePrefix(String name, Class<?> aClass) {
		return aClass.getSimpleName() + "." + name;
	}

	private String getPropertyName(String name, Field field) {
		return name + "." + field.getName();
	}
}
